OPC Studio User's Guide and Reference
Configuring the OPC UA Complex Data extension and its parts
Concepts > QuickOPC Concepts > QuickOPC Extensions > QuickOPC Integrated Extensions > OPC UA Complex Data Extension > Advanced OPC UA Complex Data Tasks > Configuring the OPC UA Complex Data extension and its parts
In This Topic

There are various parameters that can be configured on the OPC UA Complex Data extension. Take following steps to read or modify them:

  1. Access the InstanceParameters Property of your EasyUAClient Class instance.
  2. In the InstanceParameters Property, access the PluginConfigurations Property.
  3. Call the Find Method of the ConfigurationPartCollection Class, passing it the name of the type of the configuration part you want to modify. The available type names and their purposes are listed further below.
  4. Read or modify the properties of the obtained object as needed.

Some typical scenarios for which the configuration might be needed are described below.

Configuring the extension only has effect when done before you attempt first OPC operation or GetService Method call on the object instance.

Using shared data type model provider

The data type model provider (DTMP) is an object that provides access to the metadata about data type in the target OPC server(s). The data type model provider also caches the metadata obtained, so that repeated decodings of the same data types do not require retrieving the metadata from the OPC server(s) again and again.

By default, each instance of the EasyUAClient Class has its own data type model provider. If you use multiple instances of the EasyUAClient Class and do not require them be fully isolated in this respect, you should consider switching to a shared data type model provider.

Conceptually, there is no noticeable difference in the results from the default state in which the client objects are set to use per-instance data type model provider. But, with the shared data type model provider, the metadata obtained during the operations on one client object and cached inside the data type model provider are reused during operations on other client objects, making this and the subsequent operations more efficient.

The configuration part that you need to access is the UAComplexDataClientPluginParameters Class.

.NET

// Shows how to configure the OPC UA Complex Data plug-in to use a shared data type model provider.
//
// Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .
// OPC client and subscriber examples in C# on GitHub: https://github.com/OPCLabs/Examples-QuickOPC-CSharp .
// Missing some example? Ask us for it on our Online Forums, https://www.opclabs.com/forum/index ! You do not have to own
// a commercial license in order to use Online Forums, and we reply to every post.

using System;
using System.Diagnostics;
using OpcLabs.EasyOpc.UA;
using OpcLabs.EasyOpc.UA.OperationModel;
using OpcLabs.EasyOpc.UA.Plugins.ComplexData;

namespace UADocExamples.ComplexData._UAComplexDataClientPluginParameters
{
    class IsolatedDataTypeModelProvider
    {
        public static void Main1()
        {
            // Define which server and node we will work with.
            UAEndpointDescriptor endpointDescriptor =
                "opc.tcp://opcua.demo-this.com:51210/UA/SampleServer";
            // or "http://opcua.demo-this.com:51211/UA/SampleServer" (currently not supported)
            // or "https://opcua.demo-this.com:51212/UA/SampleServer/"
            UANodeDescriptor nodeDescriptor =
                "nsu=http://test.org/UA/Data/ ;i=10239"; // [ObjectsFolder]/Data.Static.Scalar.StructureValue


            // We will create two instances of EasyUAClient class, and configure each of them to use the shared data type
            // model provider.

            // Configure the first client object.
            var client1 = new EasyUAClient();
            UAComplexDataClientPluginParameters complexDataClientPluginParameters1 =
                client1.InstanceParameters.PluginConfigurations.Find<UAComplexDataClientPluginParameters>();
            Debug.Assert(complexDataClientPluginParameters1 != null);
            complexDataClientPluginParameters1.IsolatedDataTypeModelProvider = false;

            // Configure the second client object.
            var client2 = new EasyUAClient();
            UAComplexDataClientPluginParameters complexDataClientPluginParameters2 =
                client2.InstanceParameters.PluginConfigurations.Find<UAComplexDataClientPluginParameters>();
            Debug.Assert(complexDataClientPluginParameters2 != null);
            complexDataClientPluginParameters2.IsolatedDataTypeModelProvider = false;


            // We will now read the same complex data node using the two client objects.
            //
            // There is no noticeable difference in the results from the default state in which the client objects are
            // set to use per-instance data type model provider. But, with the shared data type model provider, the metadata
            // obtained during the read on the first client object and cached inside the data type model provider are reused
            // during the read on the second client object, making this and the subsequent operations more efficient.

            // Read the complex data node using the first client.
            object value1;
            try
            {
                value1 = client1.ReadValue(endpointDescriptor, nodeDescriptor);
            }
            catch (UAException uaException)
            {
                Console.WriteLine("*** Failure: {0}", uaException.GetBaseException().Message);
                return;
            }
            Console.WriteLine(value1);

            // Read the complex data node using the second client.
            object value2;
            try
            {
                value2 = client2.ReadValue(endpointDescriptor, nodeDescriptor);
            }
            catch (UAException uaException)
            {
                Console.WriteLine("*** Failure: {0}", uaException.GetBaseException().Message);
                return;
            }
            Console.WriteLine(value2);
        }
    }
}
' Shows how to configure the OPC UA Complex Data plug-in to use a shared data type model provider.
'
' Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .
' OPC client and subscriber examples in VB.NET on GitHub: https://github.com/OPCLabs/Examples-QuickOPC-VBNET .
' Missing some example? Ask us for it on our Online Forums, https://www.opclabs.com/forum/index ! You do not have to own
' a commercial license in order to use Online Forums, and we reply to every post.

Imports System
Imports OpcLabs.EasyOpc.UA
Imports OpcLabs.EasyOpc.UA.OperationModel
Imports OpcLabs.EasyOpc.UA.Plugins.ComplexData

Namespace ComplexData._UAComplexDataClientPluginParameters

    Friend Class IsolatedDataTypeModelProvider

        Public Shared Sub Main1()

            ' Define which server we will work with.
            Dim endpointDescriptor As UAEndpointDescriptor =
                    "opc.tcp://opcua.demo-this.com:51210/UA/SampleServer"
            ' or "http://opcua.demo-this.com:51211/UA/SampleServer" (currently not supported)
            ' or "https://opcua.demo-this.com:51212/UA/SampleServer/"

            ' Define which node we will work with.
            Dim nodeDescriptor As UANodeDescriptor =
                "nsu=http://test.org/UA/Data/ ;i=10239"  ' [ObjectsFolder]/Data.Static.Scalar.StructureValue


            ' We will create two instances of EasyUAClient class, and configure each of them to use the shared data type
            ' model provider.

            ' Configure the first client object.
            Dim client1 = New EasyUAClient
            Dim complexDataClientPluginParameters1 As UAComplexDataClientPluginParameters =
                client1.InstanceParameters.PluginConfigurations.Find(Of UAComplexDataClientPluginParameters)()
            Debug.Assert(complexDataClientPluginParameters1 IsNot Nothing)
            complexDataClientPluginParameters1.IsolatedDataTypeModelProvider = False

            ' Configure the second client object.
            Dim client2 = New EasyUAClient
            Dim complexDataClientPluginParameters2 As UAComplexDataClientPluginParameters =
                client2.InstanceParameters.PluginConfigurations.Find(Of UAComplexDataClientPluginParameters)()
            Debug.Assert(complexDataClientPluginParameters2 IsNot Nothing)
            complexDataClientPluginParameters2.IsolatedDataTypeModelProvider = False


            ' We will now read the same complex data node using the two client objects.
            '
            ' There is no noticeable difference in the results from the default state in which the client objects are
            ' set to use per-instance data type model provider. But, with the shared data type model provider, the metadata
            ' obtained during the read on the first client object and cached inside the data type model provider are reused
            ' during the read on the second client object, making this and the subsequent operations more efficient.

            ' Read the complex data node using the first client.
            Dim value1 As Object
            Try
                value1 = client1.ReadValue(endpointDescriptor, nodeDescriptor)
            Catch uaException As UAException
                Console.WriteLine("*** Failure: {0}", uaException.GetBaseException.Message)
                Exit Sub
            End Try
            Console.WriteLine(value1)

            ' Read the complex data node using the second client.
            Dim value2 As Object
            Try
                value2 = client2.ReadValue(endpointDescriptor, nodeDescriptor)
            Catch uaException As UAException
                Console.WriteLine("*** Failure: {0}", uaException.GetBaseException.Message)
                Exit Sub
            End Try
            Console.WriteLine(value2)
        End Sub
    End Class
End Namespace

COM

// Shows how to configure the OPC UA Complex Data plug-in to use a shared data type model provider.
//
// Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .
// OPC client and subscriber examples in Object Pascal (Delphi) on GitHub: https://github.com/OPCLabs/Examples-QuickOPC-OP .
// Missing some example? Ask us for it on our Online Forums, https://www.opclabs.com/forum/index ! You do not have to own
// a commercial license in order to use Online Forums, and we reply to every post.

class procedure IsolatedDataTypeModelProvider.Main;
var
  Client1, Client2: _EasyUAClient;
  ComplexDataClientPluginParameters1, ComplexDataClientPluginParameters2: OpcLabs_EasyOpcUA_TLB._UAComplexDataClientPluginParameters;
  EndpointDescriptor: string;
  NodeDescriptor: string;
  Value1, Value2: OleVariant;
begin
  // Define which server and node we will work with.
  EndpointDescriptor := 
    //'http://opcua.demo-this.com:51211/UA/SampleServer';
    //'https://opcua.demo-this.com:51212/UA/SampleServer/';
    'opc.tcp://opcua.demo-this.com:51210/UA/SampleServer';
  NodeDescriptor := 'nsu=http://test.org/UA/Data/ ;i=10239';  // [ObjectsFolder]/Data.Static.Scalar.StructureValue

  // We will create two instances of EasyUAClient class, and configure each of them to use the shared data type
  // model provider.

  // Configure the first client object.
  Client1 := CoEasyUAClient.Create;
  ComplexDataClientPluginParameters1 := IUnknown(Client1.InstanceParameters.PluginConfigurations.Find('OpcLabs.EasyOpc.UA.Plugins.ComplexData.UAComplexDataClientPluginParameters')) as OpcLabs_EasyOpcUA_TLB._UAComplexDataClientPluginParameters;
  ComplexDataClientPluginParameters1.IsolatedDataTypeModelProvider := false;

  // Configure the second client object.
  Client2 := CoEasyUAClient.Create;
  ComplexDataClientPluginParameters2 := IUnknown(Client2.InstanceParameters.PluginConfigurations.Find('OpcLabs.EasyOpc.UA.Plugins.ComplexData.UAComplexDataClientPluginParameters')) as OpcLabs_EasyOpcUA_TLB._UAComplexDataClientPluginParameters;
  ComplexDataClientPluginParameters2.IsolatedDataTypeModelProvider := false;

  // We will now read the same complex data node using the two client objects.
  //
  // There is no noticeable difference in the results from the default state in which the client objects are
  // set to use per-instance data type model provider. But, with the shared data type model provider, the metadata
  // obtained during the read on the first client object and cached inside the data type model provider are reused
  // during the read on the second client object, making this and the subsequent operations more efficient.

  // Read the complex data node using the first client.
  try
    Value1 := Client1.ReadValue(EndpointDescriptor, NodeDescriptor);
  except
    on E: EOleException do
    begin
      WriteLn(Format('*** Failure: %s', [E.GetBaseException.Message]));
      Exit;
    end;
  end;
  WriteLn(Value1);

  // Read the complex data node using the second client.
  try
    Value2 := Client2.ReadValue(EndpointDescriptor, NodeDescriptor);
  except
    on E: EOleException do
    begin
      WriteLn(Format('*** Failure: %s', [E.GetBaseException.Message]));
      Exit;
    end;
  end;
  WriteLn(Value2);

end;
Rem Shows how to configure the OPC UA Complex Data plug-in to use a shared data type model provider.
Rem
Rem Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .
Rem OPC client and subscriber examples in VBScript on GitHub: https://github.com/OPCLabs/Examples-QuickOPC-VBScript .
Rem Missing some example? Ask us for it on our Online Forums, https://www.opclabs.com/forum/index ! You do not have to own
Rem a commercial license in order to use Online Forums, and we reply to every post.

Option Explicit

' Define which server and node we will work with.
Dim endpointDescriptor: endpointDescriptor = _
    "opc.tcp://opcua.demo-this.com:51210/UA/SampleServer"
    '"http://opcua.demo-this.com:51211/UA/SampleServer"  
    '"https://opcua.demo-this.com:51212/UA/SampleServer/"
Dim nodeDescriptor: nodeDescriptor = _
    "nsu=http://test.org/UA/Data/ ;i=10239"  ' [ObjectsFolder]/Data.Static.Scalar.StructureValue


' We will create two instances of EasyUAClient class, and configure each of them to use the shared data type
' model provider.

' Configure the first client object.
Dim Client1: Set Client1 = CreateObject("OpcLabs.EasyOpc.UA.EasyUAClient")
Dim ComplexDataClientPluginParameters1: Set ComplexDataClientPluginParameters1 = Client1.InstanceParameters.PluginConfigurations.Find( _
    "OpcLabs.EasyOpc.UA.Plugins.ComplexData.UAComplexDataClientPluginParameters")
ComplexDataClientPluginParameters1.IsolatedDataTypeModelProvider = False

' Configure the second client object.
Dim Client2: Set Client2 = CreateObject("OpcLabs.EasyOpc.UA.EasyUAClient")
Dim ComplexDataClientPluginParameters2: Set ComplexDataClientPluginParameters2 = Client2.InstanceParameters.PluginConfigurations.Find( _
    "OpcLabs.EasyOpc.UA.Plugins.ComplexData.UAComplexDataClientPluginParameters")
ComplexDataClientPluginParameters2.IsolatedDataTypeModelProvider = False

' We will now read the same complex data node using the two client objects.
'
' There is no noticeable difference in the results from the default state in which the client objects are
' set to use per-instance data type model provider. But, with the shared data type model provider, the metadata
' obtained during the read on the first client object and cached inside the data type model provider are reused
' during the read on the second client object, making this and the subsequent operations more efficient.

' Read the complex data node using the first client.
On Error Resume Next
Dim Value1: Set Value1 = Client1.ReadValue(endpointDescriptor, nodeDescriptor)
If Err.Number <> 0 Then
    WScript.Echo "*** Failure: " & Err.Source & ": " & Err.Description
    WScript.Quit
End If
On Error Goto 0
WScript.Echo Value1

' Read the complex data node using the second client.
On Error Resume Next
Dim Value2: Set Value2 = Client2.ReadValue(endpointDescriptor, nodeDescriptor)
If Err.Number <> 0 Then
    WScript.Echo "*** Failure: " & Err.Source & ": " & Err.Description
    WScript.Quit
End If
On Error Goto 0
WScript.Echo Value2

Python

# Shows how to configure the OPC UA Complex Data plug-in to use a shared data type model provider.
#
# Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .
# OPC client and subscriber examples in Python on GitHub: https://github.com/OPCLabs/Examples-QuickOPC-Python .
# Missing some example? Ask us for it on our Online Forums, https://www.opclabs.com/forum/index ! You do not have to own
# a commercial license in order to use Online Forums, and we reply to every post.
# The QuickOPC package is needed. Install it using "pip install opclabs_quickopc".
import opclabs_quickopc

# Import .NET namespaces.
from System import *
from OpcLabs.EasyOpc.UA import *
from OpcLabs.EasyOpc.UA.OperationModel import *
from OpcLabs.EasyOpc.UA.Plugins.ComplexData import *


endpointDescriptor = UAEndpointDescriptor('opc.tcp://opcua.demo-this.com:51210/UA/SampleServer')
# or 'http://opcua.demo-this.com:51211/UA/SampleServer' (currently not supported)
# or 'https://opcua.demo-this.com:51212/UA/SampleServer/'

# [ObjectsFolder]/Data.Static.Scalar.StructureValue
nodeDescriptor = UANodeDescriptor('nsu=http://test.org/UA/Data/ ;i=10239')


# We will create two instances of EasyUAClient class, and configure each of them to use the shared data type
# model provider.

# Configure the first client object.
client1 = EasyUAClient()
complexDataClientPluginParameters1 = (
    client1.InstanceParameters.PluginConfigurations.Find[UAComplexDataClientPluginParameters]())
assert complexDataClientPluginParameters1 is not None
complexDataClientPluginParameters1.IsolatedDataTypeModelProvider = False

# Configure the second client object.
client2 = EasyUAClient()
complexDataClientPluginParameters2 = (
    client1.InstanceParameters.PluginConfigurations.Find[UAComplexDataClientPluginParameters]())
assert complexDataClientPluginParameters2 is not None
complexDataClientPluginParameters1.IsolatedDataTypeModelProvider = False


# We will now read the same complex data node using the two client objects.
#
# There is no noticeable difference in the results from the default state in which the client objects are
# set to use per-instance data type model provider. But, with the shared data type model provider, the metadata
# obtained during the read on the first client object and cached inside the data type model provider are reused
# during the read on the second client object, making this and the subsequent operations more efficient.

# Read the complex data node using the first client.
try:
    value1 = IEasyUAClientExtension.ReadValue(client1, endpointDescriptor, nodeDescriptor)
except UAException as uaException:
    print('*** Failure: ' + uaException.GetBaseException().Message)
    exit()
print(value1)

# Read the complex data node using the second client.
try:
    value2 = IEasyUAClientExtension.ReadValue(client2, endpointDescriptor, nodeDescriptor)
except UAException as uaException:
    print('*** Failure: ' + uaException.GetBaseException().Message)
    exit()
print(value1)


print()
print('Finished.')

 

Configuring data type dictionary locations

In OPC Binary data type system, data type dictionaries that reside in the OPC server may use types from other data type dictionaries, and optionally specify location of these other dictionaries, using a string. The OPC UA specification does not define a format for such string.

The OPC UA Complex Data extension already contains data the standard data type dictionary defined in the OPC UA specification, and some others. It also knows how to resolve their namespaces to locations, therefore (by default), the data type dictionaries in the server do not have to specify the location for them.

For other namespaces, the OPC Binary data type system recognizes following syntax for the location string:

If the location string is understood to be a URI, it can be only:

For import directives that do not have their location string specified, the OPC Binary data type system tries to find the location in the WellKnownLocationTemplateDictionary Property. You can therefore access the UAOpcBinaryDtsParameters Class configuration part, and add your entry (entries) to this dictionary, in order to tell the OPC Binary data type system where to find the data type dictionaries. You can specify a node ID in the server if the data type dictionary resides there, or place the data type dictionary into a file, or embed it in a managed resource in your program.

Working around errors in data type dictionaries

The OPC UA Complex Data is commonly implemented with some bugs on the server side. In addition, at time of writing this article, it is not rigorously (or at all) checked during OPC compliance certification process, and only to very limited extent during OPC Interoperability Workshops. The client must therefore be prepared to handle situations in which the server behavior is erroneous.

We have tested the OPC UA Complex Data extension against several servers with complex data support available, and continue to expand the range of interoperable servers. We have found several issues in these servers (and in the OPC UA specifications) during these tests, and have already provided special coding and configuration inside the OPC UA Complex Data extension to work around these issues.

If you encounter a buggy server and the workaround is not already built into the OPC UA Complex Data extension, you might be able to work around the problem by configuring the extension accordingly. You are also welcome to report the problem to us, so that we can adjust the software and prevent the issue in future versions.

For errors related to the OPC Binary data type system, the configuration part you need to access is the UAOpcBinaryDtsParameters Class.

Here are some common issues with OPC Binary data type system, and their possible workarounds:

 

See Also

Reference